#pragma once

#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<strings.h>
#include<functional>
#include"Logger.hpp"

using callback_t = std::function<std::string(\
                const std::string& word , const std::string& wordip , uint16_t wordport)>;

static const int gdefaultsockfd = -1;

class DictServer
{
public:
    DictServer( uint16_t port , callback_t cb)
        :_port(port)
        ,_cb(cb)
        ,_is_running(false)
        ,_sockfd(gdefaultsockfd)
    {}
    ~DictServer()
    {}

    //初始化 -> 创建套接字，并与ip 端口号绑定
    void Init()
    {
        _sockfd = socket(AF_INET , SOCK_DGRAM , 0);
        //文件描述符
        if(_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "创建 socket 失败" ;
            exit(0);
        }
        LOG(LogLevel::INFO) << "创建 socket 成功" ;

        //绑定ip 和端口号
        struct sockaddr_in local;
        bzero(&local , sizeof(local));
        local.sin_family = AF_INET;
        //主机转网络
        local.sin_port = htons(_port);
        // local.sin_addr.s_addr = inet_addr(_ip.c_str());//绑定固定的ip ，ip 在网络中传输用的是4字节整数
        //不绑定固定的ip,而是绑定这个机子中的任意ip , 可以理解为将机子的所有ip 均绑定
        local.sin_addr.s_addr = htonl(INADDR_ANY);

        //bind
        int n = bind(_sockfd , (struct sockaddr*)&local , sizeof(local));//成功返回0，失败返回-1
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "绑定 socket 失败" ;
            exit(0);
        }
        LOG(LogLevel::DEBUG) << "绑定 socket 成功" ;
    }
    //启动服务 -> 读取文件中的数据、处理数据、返回数据
    void Start()
    {
        //服务器是一个死循环
        _is_running = true;
        while(_is_running)
        {
            char buffer[1024];
            struct sockaddr_in peer;//输出型参数
            socklen_t len = sizeof(peer);//输出、输入型参数
            //从文件中读取数据-> recvfrom ，返回值为读取到的数据个数, 同时会读取到发送方的信息
            int n = recvfrom(_sockfd ,buffer , sizeof(buffer) , 0, (struct sockaddr*)&peer , &len);
            if(n > 0)
            {
                //需要将从文件中读取到的字符串手动加上 \0
                buffer[n] =0;
                //成功读取到了数据
                //处理数据  -> 模块化处理
                std::string word = buffer;
                // std::cout << "用户查找：" << buffer <<std::endl;
                //将获取到发送放的 ip port 网络转主机处理
                uint16_t wordport = ntohs(peer.sin_port);
                std::string wordip = inet_ntoa(peer.sin_addr);

                std::string result = _cb(word ,wordip,wordport);
                std::cout <<'[' << wordip << ":" << wordport << ']' << "客户 say# " << buffer << std::endl;

                //向发送方返回处理过后的数据 -> sendto
                sendto(_sockfd , result .c_str(),result.size() , 0 ,(struct sockaddr*)&peer, sizeof(peer));
            }
        }
        _is_running = false;
    }

private:
    int _sockfd;
    //端口号、ip
    uint16_t _port;
    // std::string _ip;//点分十进制ip 
    bool _is_running;

    callback_t _cb;//回调方法
};